const fs = require('fs');
const path = require('path');
const babel = require('@babel/core');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse');

const getModuleInfo = filePath => {
    // 使用 fs 读取文件内容
    const body = fs.readFileSync(filePath, 'utf-8');

    // 使用 @babel/parse 把文件内容解析为 ast 语法树
    const ast = parser.parse(body, {
        sourceType: 'module'
    });

    // 使用 @babel/reaverse 解析所有依赖路径
    const deps = {};
    traverse.default(ast, {
        ImportDeclaration({
            node
        }) {

            const dirname = path.dirname(filePath)
            const abspath = './' + path.join(dirname, node.source.value)
            deps[node.source.value] = abspath
        }
    });

    // 使用 @babel/core 和 @babel/preset-env 把 ast 语法树 转化为 es5 代码
    const { code } = babel.transformFromAst(ast, null, {
        presets:['@babel/preset-env']
    });

    // 返回模块信息
    return { filePath, deps, code };
}

const getAllModules = (filePath) => {
    const entry = getModuleInfo(filePath);
    const temp = [entry];
    for (let i = 0; i < temp.length; i++){
        const deps = temp[i].deps;
        for (const key in deps) {
            if (deps.hasOwnProperty(key)) {
                temp.push(getModuleInfo(deps[key]));
            }
        }
    }
    const modules = {};
    temp.forEach(module => {
        modules[module.filePath] = { code: module.code, deps: module.deps };
    })
    return modules;
}

const bundleModules = (filePath) => {
    const depsGraph = JSON.stringify(getAllModules(filePath));
    const bundledStr =
`/* -------- my-wb-bundle -------- */

(function (depsGraph) {
    // 定义 require 方法
    function require (filePath) {
        // 先将模块内依赖的文件路径转换为绝对路径后调用 require 方法
        function absRequire (relPath) {
            return require(depsGraph[filePath].deps[relPath]);
        };

        // 定义 exports 对象
        var exports = {};

        // 将 code 写入到 exports 对象
        (function (require, exports, code){
            eval(code);
        })(absRequire, exports, depsGraph[filePath].code);

        // 到出 exports 对象
        return exports;
    }

    // require 调用入口文件
    require('${filePath}');

// 传入依赖图
})(${depsGraph})

/* ------- my-wb-bundle -------- */`;
    return bundledStr;
};

const bundledContent = bundleModules('./src/index.js');

fs.writeFileSync('./dist/bundle.js', bundledContent);
